﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VsxFactory.Modeling.VisualStudio;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.Modeling;
using System.ComponentModel;
using VsxFactory.Modeling.Strategies.Rules;

namespace VsxFactory.Modeling.Strategies
{
    public interface IProjectSelector
    {
        IVsProject GetProjectNode(IStrategyContext context, GenerationSpec targetElement);
    }

    public class PathFilter
    {
        [DefaultValue(null)]
        public string Path { get; set; }
        [DefaultValue(null)]
        public object Value { get; set; }
        public Type TargetType { get; set; }
        [DefaultValue("EQ")]
        public string Operator { get; set; }

        public PathFilter()
        {
            Operator = "EQ";
        }

        protected bool CheckPath(IStrategyContext context, GenerationSpec targetElement, out Tuple<GenerationSpec, DomainPropertyInfo> result)
        {
            if (Operator != "EQ" && Operator != "NE")
                throw new Exception("Invalid operator (must be EQ or NE)");

            result = null;
            bool flag = false;
            var tuple = PathUtilities.GetElement(context, targetElement, Path);
            if (tuple == null)
                return false;

            if (tuple.Item2 == null)
            {
                DomainClassInfo domainClass = tuple.Item1.ModelElement.GetDomainClass();
                flag = domainClass.ImplementationClass.IsAssignableFrom(TargetType);
            }
            else
            {
                var prop = tuple.Item2;
                if (prop == null && prop.PropertyInfo.PropertyType != TargetType)
                    return false;
                var propertyValue = prop.GetValue(tuple.Item1.ModelElement);
                if (propertyValue == null)
                    flag = Value == null;
                else
                    flag = propertyValue.Equals(Value);
            }

            if (Operator == "EQ" ? flag : !flag)
            {
                result = tuple;
                return true;
            }
            return false;
        }
    }

    public class ModelSelector : PathFilter, IProjectSelector
    {
        public IVsProject GetProjectNode(IStrategyContext context, GenerationSpec targetElement)
        {
            if (!String.IsNullOrWhiteSpace(Path) && TargetType != null)
            {
                var project = targetElement.ModelElement.Store.ElementDirectory.AllElements.Where(e => e.GetType() == TargetType).FirstOrDefault();
                if (project == null)
                    return null;
                return context.Strategy.CreateGenerationSpec(context, project).GenerationProject;
            }

            Tuple<GenerationSpec, DomainPropertyInfo> result;
            if( CheckPath(context, targetElement, out result))
            {
                return result.Item1.GenerationProject;
            }
            return null;
        }
    }

    public class SolutionSelector : IProjectSelector
    {
        private string pattern;
        private Regex regex;

        public string Pattern { get { return pattern; } set { pattern = value; regex = new Regex(pattern); } }

        public IVsProject GetProjectNode( IStrategyContext context, GenerationSpec targetElement)
        {
            var query = from node in context.SolutionExplorer.CurrentSolution.AllElements.OfType<IVsProject>()
                        where IsMatch(node.Name)
                        select node;
            return query.FirstOrDefault();
        }

        private bool IsMatch(string name)
        {
            return regex.IsMatch(name);
        }
    }
}
